package com.cloudfun.campusshare.configuration.config;

import com.cloudfun.campusshare.common.constant.Code;
import com.cloudfun.campusshare.common.exception.AccessDenyException;
import com.cloudfun.campusshare.common.exception.AuthenticationException;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.common.response.BaseResult;
import com.cloudfun.campusshare.common.response.BaseResultFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Created by Huqin on 2019/12/11
 */
@ControllerAdvice
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler(value = AuthenticationException.class)
    public void authenticationException(AuthenticationException e, HttpServletResponse httpServletResponse) {
        log.error("认证异常：", e);
        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    }

    @ExceptionHandler(value = AccessDenyException.class)
    public void accessDenyException(AccessDenyException e, HttpServletResponse httpServletResponse) {
        log.error("鉴权异常：", e);
        httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
    }

    @ExceptionHandler(value = BusinessException.class)
    public BaseResult<?> businessException(BusinessException e) {
        log.error("业务异常", e);
        return e.getBaseResult();
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public BaseResult<String> methodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error("参数校验异常 : " + e);
        BindingResult result = e.getBindingResult();
        List<FieldError> fieldErrors = result.getFieldErrors();
        String errorMsg = fieldErrors.stream().map(FieldError::getDefaultMessage).collect(Collectors.joining("\n"));
        return BaseResultFactory.produceResult(Code.PARAMETER_ERROR, errorMsg);
    }

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public BaseResult<String> missingServletRequestParameterException(MissingServletRequestParameterException e) {
        log.error("参数缺失异常 : " + e);
        String parameterName = e.getParameterName();
        return BaseResultFactory.produceResult(Code.PARAMETER_ERROR, "'" + parameterName + " is not present");
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public BaseResult<String> constraintViolationException(ConstraintViolationException e) {
        log.error("方法参数校验异常 : " + e);
        Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
        String errorMsg = constraintViolations.stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("\n"));
        return BaseResultFactory.produceResult(Code.PARAMETER_ERROR, errorMsg);
    }

    @ExceptionHandler(value = {HttpMessageNotReadableException.class})
    public BaseResult<?> httpMessageNotReadableException(HttpMessageNotReadableException e) {
        log.error("参数类型错误", e);
        return BaseResultFactory.produceEmptyResult(Code.PARAMETER_NOT_READABLE);
    }

    @ExceptionHandler(value = {HttpRequestMethodNotSupportedException.class})
    public void httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e, HttpServletResponse httpServletResponse) {
        log.error("http请求方法错误", e);
        httpServletResponse.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
    }

    @ExceptionHandler(value = RuntimeException.class)
    public BaseResult<String> runtimeExceptionHandler(RuntimeException e) {
        log.error("运行时异常", e);
        return BaseResultFactory.produceResult(Code.SYSTEM_ERROR, null);
    }

    @ExceptionHandler(value = Exception.class)
    public BaseResult<String> exception(Exception e) {
        log.error("未知异常", e);
        return BaseResultFactory.produceResult(Code.SYSTEM_ERROR, null);
    }
}
